// TODO
// user-index of clicked place in canvas
// various text styles: font, rotated, curtailed text if it dsnt fit
// point shapes
// band end styles
// hover events
// listen to das servers....

// Each feature is either a point feature or a range, this is indicated by presence of start and end, or just start.
// Feature coordinates are given in user coordinate system and they are translated to canvas coordinates before rendering.
// User to actual coordinate scaling factor has to be integer >= 1, or it is forced to be 1.

function BandAnnotator(configs) {
	var me = this;
	for(cfk in configs) me[cfk] = configs[cfk];
	me.feature2objects = {};

	// scale x-length from user to canvas coordinates
	me.canvasdx = function(dx) { return me.scale*dx;};
	// scale x-position from user to canvas coordinates
	me.canvasx = function(x) { return me.startx + me.scale*x;};
	// scale y-position from user to canvas coodinates
	me.canvasy = function(y) { return me.scale*y;};

	// finds x-scaling from user to canvas dimension.
	// calls renderers for everything, attaches click functions
	// if user-provided x-start / end are not within 0...length then band is skipped with an alert
	me.render = function() {
		me.paper = Raphael(document.getElementById(me.container), me.canvasWidth, me.canvasHeight);
		me.startx = 10; // margin in canvas units, leave at least this at both ends to have space for end annotations
		me.scale = Math.floor((me.canvasWidth-2*me.startx)/me.length); // note this may lead to much gap at right end
		if(me.scale < 1) me.scale = 1;
		for(var fri in me.features) {
			var fr = me.features[fri];
			// skip any features that have ambiguous starts or ends
			if( (!fr.start && !fr.end) || (fr.start && (fr.start < 0 || fr.start >= me.length)) || (fr.end && (fr.end < 0 || fr.end >= me.length)) ) {
				alert("Skipping out of bounds feature, start end length: " + fr.start + " " + fr.end + " " + me.length); continue;
			}
			var frobjs = [];
			if(fr.type == 'full') frobjs = me.drawWhole(fr);
			if(fr.type == 'band') frobjs = me.drawBand(fr);
			if(fr.type == 'point') frobjs = me.drawPoint(fr);
			if(fr.type == 'bridge') frobjs = me.drawBridge(fr);
			me.feature2objects[fr.metadata.featurename] = frobjs;
			if(fr.mouseclick && frobjs.length > 0) {
				for(var fi=0; fi < frobjs.length; fi++) {
					fr.metadata['bandAnnotatorObject'] = me;
					frobjs[fi].attrs.metadata = fr.metadata;
					frobjs[fi].click( function(ev) { fr.mouseclick(ev); } );
				}
			}
		}
	};

	// hide or show listed features; all features if none provided...
	me.featureHideShow = function(fnames, hideORshow) {
		for(var fn in me.feature2objects) {
			if(fnames) {
				var hasFname = 0;
 				for(var fni in fnames)
					if(fn == fnames[fni]) { hasFname = 1; break; }
				if(hasFname == 0) continue;
			}
			var frobs = me.feature2objects[fn];
			for(var fi=0; fi < frobs.length; fi++)
				if(hideORshow == "show") frobs[fi].show();
				else                     frobs[fi].hide();
		}
	}

	// called from .show() for drawing a graphic of class band
	// return 1 or more objects on which mouse events are to be set for this band
	me.drawBand = function(fr) {
		var topleftX = me.canvasx(fr.start); // x-extents
		var width = me.canvasdx(fr.end-fr.start);
		var vstart = me.percentToNumber( (fr.vstart ? fr.vstart : '30%'), 0.3 ); // y-extents
		var vend = me.percentToNumber( (fr.vend ? fr.vend : '70%'), 0.7 );
		var topleftY = me.canvasHeight * vstart;
		var height = me.canvasHeight * (vend-vstart);
		var frobjs = [];
		var rect = me.paper.rect( topleftX, topleftY, width, height ); rect.attr({fill:fr.color});
		frobjs.push(rect);
		if(fr.text) { frobjs.push(me.paper.text(topleftX+width/2, topleftY+height/2, fr.text)); }
		return frobjs;
	};
	me.drawPoint = function() { return []; }
	me.drawBridge = function() { return []; }

	// convert a percentage string like ' 20 % ' etc to 0.2. Return default value of conversion is unsuccessful
	me.percentToNumber = function(x, defaultValue) {
		x = x.replace(/ /, '');
		x = x.replace(/%,*/, '');
		try { return Number(x)/100.; }
		catch(e) { return defaultValue; }
	}
	// convert to user's X coordinates...
	me.toUserX = function(canvasX) { }
	me.raphaMouseEventToBandFractionalXY = function(raphaevent) {
		// TODO have to check for replacemenents to x,y.. dsnt seem correct... pageX, clientX ?
		var ex = raphaevent.target.raphael.attrs['x'];
		var ey = raphaevent.target.raphael.attrs['y'];
		var ew = raphaevent.target.raphael.attrs['width'];
		var eh = raphaevent.target.raphael.attrs['height'];
		// event click location TODO check
		var vx = raphaevent['pageX'] - document.getElementById(me.container).offsetLeft;
		var vy = raphaevent['pageY'] - document.getElementById(me.container).offsetTop;
		//alert(ex + " " + ey + " " + ew + " " + eh + " " + vx + " " + vy);
		var fx = (vx-ex) / ew , fy = (vy-ey) / eh ;
		if(fx < 0) fx = 0;
		if(fx > 1) fx = 1;
		if(fy < 0) fy = 0;
		if(fy > 1) fy = 1;
		return [ fx, fy ];
	}
	return me;
}
